/*
 * @Date: 2021-11-17 14:29:41
 * @LastEditTime: 2021-11-17 22:24:37
 * @FilePath: \tcp_client\main.go
 * @Description: 入口文件
 */
package main

import (
	"bufio"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"net"
	"os"
	"strings"
	"time"

	"github.com/chatroom_client/codec"
)

func main() {
	var port string
	input := bufio.NewScanner(os.Stdin)

	flag.StringVar(&port, "port", "127.0.0.1:8888", "server port")
	conn, err := net.Dial("tcp", port)
	if err != nil {
		fmt.Println("Error connecting:", err)
		os.Exit(1)
	}
	defer conn.Close()
	fmt.Println("Connecting to " + port)

	var ch = make(chan codec.Packet, 1000)
	go write(conn, ch)

	var count int64
	var userName string

	for {
		count++
		fmt.Println("请输入用户名称:")

		input.Scan()
		userName = input.Text()

		var s = &codec.Submit{
			ID:      fmt.Sprintf("%08d", count),
			Payload: []byte(fmt.Sprintf(`{"event_id":"login","data":{"user_name":"%s"}}`, userName)),
		}

		ch <- s

		if err := readOnce(conn); err != nil {
			fmt.Println(err.Error())
			continue
		} else {
			break
		}
	}

	go read(conn)

	var message string

	for {
		count++
		fmt.Println("请输入消息内容:")
		input.Scan()
		message = input.Text()

		if len(message) == 0 {
			continue
		}

		if message == "quit" {
			close(ch)
			conn.Close()
			return
		}

		if strings.HasPrefix(message, "/join") {
			var roomName = strings.Split(message, " ")
			if len(roomName) != 2 {
				fmt.Println("join room name error")
				continue
			}
			var s = &codec.Submit{
				ID:      fmt.Sprintf("%08d", count),
				Payload: []byte(fmt.Sprintf(`{"event_id":"join","data":{"room_name":"%s","user_name":"%s"}}`, roomName[1], userName)),
			}
			ch <- s
			continue
		} else if strings.HasPrefix(message, "/stats") {
			var _userName = strings.Split(message, " ")
			if len(_userName) != 2 {
				fmt.Println("stats user name error")
				continue
			}
			var s = &codec.Submit{
				ID:      fmt.Sprintf("%08d", count),
				Payload: []byte(fmt.Sprintf(`{"event_id":"message","data":{"message":"/stats %s","user_name":"%s"}}`, _userName[1], userName)),
			}
			ch <- s
			continue
		} else if strings.HasPrefix(message, "/popular") {
			var roomName = strings.Split(message, " ")
			if len(roomName) != 2 {
				fmt.Println("room name is error")
				continue
			}
			var s = &codec.Submit{
				ID:      fmt.Sprintf("%08d", count),
				Payload: []byte(fmt.Sprintf(`{"event_id":"message","data":{"message":"/popular %s","user_name":"%s"}}`, roomName[1], userName)),
			}
			ch <- s
			continue
		}

		var s = &codec.Submit{
			ID:      fmt.Sprintf("%08d", count),
			Payload: []byte(fmt.Sprintf(`{"event_id":"message","data":{"message":"%s","user_name":"%s"}}`, message, userName)),
		}

		ch <- s
	}
}

func readOnce(conn net.Conn) error {
	frameCodec := codec.NewMyFrameCodec()
	framePayload, err := frameCodec.Decode(conn)
	if err != nil {
		fmt.Println("handleConn: frame decode error:", err)
		return err
	}

	// do something with the packet
	if err := handlePacket(framePayload); err != nil {
		return err
	} else {
		return nil
	}
}

func read(conn net.Conn) error {
	frameCodec := codec.NewMyFrameCodec()

	for {
		// 数据包解码
		framePayload, err := frameCodec.Decode(conn)
		if err != nil {
			fmt.Println("handleConn: frame decode error:", err)
			return err
		}

		// do something with the packet
		handlePacket(framePayload)
	}
}

func handlePacket(framePayload []byte) error {
	var p codec.Packet
	var err error
	p, err = codec.Decode(framePayload)
	if err != nil {
		fmt.Println("handleConn: packet decode error:", err)
		return nil
	}

	switch p.(type) {
	case *codec.SubmitAck:
		submitAck := p.(*codec.SubmitAck)
		fmt.Printf("recv submit: id = %s, payload=%s\n", submitAck.ID, string(submitAck.Payload))

		if submitAck.Result != 0 {
			if submitAck.Result == 2 {
				return errors.New("名称已存在")
			}
			fmt.Println("操作失败")
			return nil
		}

		var data = make(map[string]interface{})
		if err := json.Unmarshal(submitAck.Payload, &data); err != nil {
			fmt.Println("handleConn: json decode error:", err)
			return nil
		}

		if data["event_id"] == "message" {
			var _messages = data["data"].([]interface{})
			if len(_messages) == 0 {
				return nil
			}
			for _, _message := range _messages {
				var message = _message.(map[string]interface{})
				var timezone = time.Unix(int64(message["timestamp"].(float64)), 0)
				fmt.Printf("time: %s,from: %s, message: %s", timezone.Format("2006-01-02 15:04:05"), message["from"].(string), message["message"].(string))
				fmt.Println()
			}
		} else if data["event_id"] == "join" {
			var _res = data["data"].(map[string]interface{})
			fmt.Printf("join room success, room_name: %s", _res["room_name"].(string))
			fmt.Println()
		} else if data["event_id"] == "stats" {
			var _res = data["data"].(map[string]interface{})
			var timezone = time.Unix(int64(_res["login_time"].(float64)), 0)
			fmt.Printf("login_time: %s, online_time: %d秒, room_name: %s", timezone.Format("2006-01-02 15:04:05"), int64(_res["online_time"].(float64)), _res["room_name"].(string))
			fmt.Println()
		} else if data["event_id"] == "popular" {
			var _res = data["data"].(string)
			fmt.Printf("发送频率最高的词:%s", _res)
			fmt.Println()
		}

		return nil
	default:
		return nil
	}
}

func write(conn net.Conn, ch chan codec.Packet) {
	var frameCodec = codec.NewMyFrameCodec()

	for _data := range ch {
		data, err := codec.Encode(_data)

		if err != nil {
			fmt.Println(err.Error())
			continue
		}

		err = frameCodec.Encode(conn, data)
		if err != nil {
			fmt.Println(err.Error())
			continue
		}
	}
}
